package org.fujene.memcon;

import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.fujene.diskblock.DiskBlock;
import org.fujene.diskblock.PureContentDiskBlock;
import org.fujene.diskblock.SkipPointerDiskBlock;
import org.fujene.diskblock.blockwise.BlockwiseContentDiskBlock;
import org.fujene.diskblock.blockwise.BlockwiseDictionaryDiskBlock;
import org.fujene.diskblock.blockwise.BlockwiseInvertIndexDiskBlock;
import org.fujene.memoryblock.MemoryBlock;
import org.fujene.structure.Constants;

/**
 * ディスク情報を保持します。 メモリと同じようにIDにより管理します。
 */
public class IndexDisk {
	// ファイルを置いてあるディレクトリ
	private String dir = null;

	private SortedMap<Integer, File> fileMap = null;

	public boolean isExistInList(int lookup) {
		Set<Integer> keys = fileMap.keySet();

		if (keys.contains(Integer.valueOf(lookup))) {
			return true;
		}

		return false;
	}

	public SortedMap<Integer, File> getFileMap() {
		reloadFileList();
		return fileMap;
	}

	public IndexDisk(String dir) {
		assert dir != null;

		fileMap = Collections.synchronizedSortedMap(new TreeMap<Integer, File>(
				new Comparator<Integer>() {
					@Override
					public int compare(Integer o1, Integer o2) {
						return o1.intValue() - o2.intValue();
					}
				}));

		setDir(dir);
	}

	public void setDir(String dir) {
		// あるか確認
		File f = new File(dir);

		if (f.exists() && f.isDirectory()) {
			this.dir = dir;

			reloadFileList();
		} else if (f.exists() && !f.isDirectory()) {
			System.out
					.println("Specified directory name exists, but not a directory.");
		} else {
			// ない
			if (f.mkdir()) {
				this.dir = dir;
			}
		}
	}

	public File getDescriptor(int ID) {
		return fileMap.get(Integer.valueOf(ID));
	}
	
	// Blockwise限定
	public DiskBlock getDiskblock(int ID) throws Exception{
		int blockType = getFileType(ID);
		
		switch (blockType) {
		case Constants.MEMORY_TYPE_DICT:
			return new BlockwiseDictionaryDiskBlock(getDescriptor(ID));
		case Constants.MEMORY_TYPE_SKIPPTR:
			return new SkipPointerDiskBlock(getDescriptor(ID));
		case Constants.MEMORY_TYPE_INVINDEX:
			return new BlockwiseInvertIndexDiskBlock(getDescriptor(ID));
		case Constants.MEMORY_TYPE_CONTENTS:
			return new BlockwiseContentDiskBlock(getDescriptor(ID));
		case Constants.MEMORY_TYPE_PURECONTENT:
			return new PureContentDiskBlock(getDescriptor(ID));
		default:
			return null;
		}
	}

	// ファイル一覧更新
	public void reloadFileList() {
		File dirf = new File(dir);
		File filef = null;

		if (dirf.exists() && dirf.isDirectory()) {
			// 名前から判断
			String[] fnamelist = dirf.list();
			String[] strs = null;
			Integer fileNum = null;

			// ファイルなんてなかった
			if (fnamelist == null)
				return;

			for (String str : fnamelist) {
				strs = str.split("\\.");
				if (strs.length > 0 && strs[1].equals("blk")) {
					fileNum = Integer.parseInt(strs[0]);
					if (!fileMap.containsKey(fileNum)) {
						filef = new File(this.dir + str);
						fileMap.put(fileNum, filef);
					}
				}
			}
		}
	}

	// 既存ファイルを消去
	public void dropFile(int ID) {
		// ファイルがあるか確認
		Integer IDobj = Integer.valueOf(ID);
		if (fileMap.containsKey(IDobj)) {
			File delFile = fileMap.get(IDobj);
			delFile.delete();
			fileMap.remove(IDobj);
		}
	}

	// ファイルを消す
	public void deleteFile(int blockID) {
		File f = fileMap.get(Integer.valueOf(blockID));
		if (f.exists()) {
			f.delete();
		}
	}

	public boolean isExist(int ID) {
		Set<Integer> ids = fileMap.keySet();

		for (Integer each : ids) {
			if (each.intValue() == ID)
				return true;
		}

		return false;
	}

	public int getFileType(int ID) throws Exception {
		File desc = fileMap.get(Integer.valueOf(ID));

		DiskBlock diskBlock = new DiskBlock(desc) {
			@Override
			public void readToMemory(MemoryBlock memBlock) {
				throw new NoSuchMethodError("Unimplemented method");
			}

			@Override
			public byte[] getData() {
				throw new NoSuchMethodError("Unimplemented method");
			}
		};

		return diskBlock.getType();
	}

	public String getDir() {
		return dir;
	}
}